package com.cloudbroker.bcs.platform.dav.middle.util;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.Map.Entry;

public class SignUtils {

    /** 日志 **/
    private static Logger logger = LoggerFactory.getLogger(SignUtils.class);

    private SignUtils() {
    }

    public static boolean signVerify(String appSecret, HttpServletRequest request) {
        @SuppressWarnings("unchecked")
        Map<String, String[]> map = request.getParameterMap();
        Map<String, String> data = new HashMap<>();
        for (Entry<String, String[]> entry : map.entrySet()) {
            data.put(entry.getKey(), entry.getValue()[0]);
        }
        return signVerify(appSecret, data);
    }

    public static boolean signVerify(String appSecret, Map<String, String> params) {
        Map<String, String> map = new HashMap<>();
        map.put("app_secret", appSecret);

        for (Entry<String, String> entity : params.entrySet()) {
            String key = entity.getKey();
            if (!"sign".equals(key)) {
                map.put(key, entity.getValue());
            }
        }

        String sign = sign(map);
        if (sign.equals(params.get("sign"))) {
            return true;
        }
        return false;
    }

    private static String toHexValue(byte[] messageDigest) {
        if (messageDigest == null)
            return "";
        StringBuilder hexValue = new StringBuilder();
        for (byte aMessageDigest : messageDigest) {
            int val = 0xFF & aMessageDigest;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

    /**
     *
     * @param params
     * @return
     */
    public static String sign(Map<String, String> params) {
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        String string = "";
        for (String s : keys) {
            string += params.get(s);
        }
        String sign = "";
        logger.info(string);
        try {
            sign = toHexValue(encryptMD5(string.getBytes(Charset.forName("utf-8"))));
        } catch (Exception e) {
            logger.error("md5 error", e, logger);
        }
        return sign;
    }

    /**
     * 签名工具.<br/>
     * 过滤值为blank的参数
     *
     * @param params
     * @return
     */
    public static String signNoBlank(Map<String, String> params) {
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        String string = "";
        for (String s : keys) {
            String value = params.get(s);
            if (StringUtils.isNotBlank(value)) {
                string += value;
            }
        }
        String sign = "";
        logger.info(string);
        try {
            sign = toHexValue(encryptMD5(string.getBytes(Charset.forName("utf-8"))));
        } catch (NoSuchAlgorithmException e) {
            logger.error("签名工具md5 error", e, logger);
        }
        return sign;
    }

    /**
     * 拼接参数, 忽略空值.
     *
     * @param params
     * @return
     */
    public static String buildParamsNoBlank(Map<String, String> params) {
        String sign = SignUtils.signNoBlank(params);
        params.put("sign", sign);
        params.remove("app_secret");

        StringBuilder sb = new StringBuilder();
        for (Entry<String, String> entry : params.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (StringUtils.isNotBlank(value)) {
                sb.append("&");
                sb.append(key);
                sb.append("=");
                sb.append(URLcoderUtil.encoder(value));
            }
        }
        // 删除第一个&
        if (sb.length() > 0) {
            sb.deleteCharAt(0);
        }
        return sb.toString();
    }

    private static byte[] encryptMD5(byte[] data) throws NoSuchAlgorithmException {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(data);
        return md5.digest();
    }

    public static void main(String[] args) {
        String appKey = "key";
        String appSecret = "secret";

        Map<String, String> params = new HashMap<>();
        params.put("app_key", appKey);
        params.put("app_secret", appSecret);
        params.put("date", Long.toString(new Date().getTime()) + "");

        String sign = sign(params);

        params.put("sign", sign);

        logger.info(Boolean.toString(signVerify(appSecret, params)));

    }
}
